﻿#include <QCoreApplication>
#include <QStandardPaths>
#include <QVariant>
#include <QDir>

#include "CefWebEngineCore/CefWebEngine.h"
#include "CefWebEngineCore/CefWebEnginePage.h"
#include "CefWebEnginePrivate.h"

CefWebEngine *CefWebEngine::self = nullptr;

static QString findPathInEnvPath(const QString &name)
{
    QStringList paths = qEnvironmentVariable("PATH").split(QDir::listSeparator());
    paths += qEnvironmentVariable("LD_LIBRARY_PATH").split(QDir::listSeparator());
    paths.prepend(QCoreApplication::applicationDirPath());
    for (const QString &path : paths)
    {
        for (const QFileInfo &info : QDir(path).entryInfoList(QDir::NoDotAndDotDot | QDir::AllEntries))
        {
            if (info.fileName() == name)
                return info.absoluteFilePath();
        }
    }
    return QString();
}

CefWebEngine::CefWebEngine(QObject *parent)
    : QObject(parent),
    d_ptr(new CefWebEnginePrivate(this))
{
    Q_D(CefWebEngine);
    if (self)
        qFatal("CefWebEngine already has a instace, don't create again.");

    self = this;

    QString cachePath = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
    QString subProcessPath = findPathInEnvPath("cefwebengineprocess.exe");
    QString resourcesPath = findPathInEnvPath("resources") + '/';
    QString localesPath = resourcesPath + "locales";

#if CEF_VERSION_MAJOR < 112
    CefEnableHighDPISupport();
#endif

    CefSettings settings;
    settings.no_sandbox = true;
    settings.multi_threaded_message_loop = true;
    settings.windowless_rendering_enabled = false;
    //settings.pack_loading_disabled = false;
    settings.external_message_pump = false;
    //settings.log_severity = LOGSEVERITY_DISABLE;

    CefString(&settings.browser_subprocess_path) = subProcessPath.toStdString();
    CefString(&settings.cache_path) = cachePath.toStdString();
    CefString(&settings.root_cache_path) = cachePath.toStdString();
    CefString(&settings.locale) = "zh-CN";
    CefString(&settings.resources_dir_path) = resourcesPath.toStdString();
    CefString(&settings.locales_dir_path) = localesPath.toStdString();

    d->addSwitch("use-mock-keychain");
    d->addSwitchWithValue("lang", "zh-CN");
    d->addSwitchWithValue("remote-allow-origins", "*");
    d->addSwitchWithValue("renderer-process-limit", "1");
    d->addSwitchWithValue("password-store", "basic");

    CefInitialize(CefMainArgs(GetModuleHandle(nullptr)), settings, d->mapp, nullptr);
}

CefWebEngine::~CefWebEngine()
{
    self = nullptr;
    CefShutdown();
}

CefWebEnginePage *CefWebEngine::createPage(const QUrl &url, quintptr windowId, bool init)
{
    Q_D(CefWebEngine);

    if (init)
    {
        CefWindowInfo windowInfo;
        windowInfo.SetAsChild((CefWindowHandle)windowId, CefRect(0, 0, INT_MAX, INT_MAX));

        CefBrowserSettings settings;
        CefBrowserHost::CreateBrowser(windowInfo, d->mclient, "about:blank", settings, nullptr, nullptr);
    }

    auto page = new CefWebEnginePage;
    page->setProperty("windowId", QVariant::fromValue(windowId));
    page->load(url);
    connect(page, &CefWebEnginePage::destroyed, this, [=]() {
        d->mpages.removeAll(page);
    });
    d->mpages.append(page);
    return page;
}

void CefWebEngine::setDevToolsPage(CefWebEnginePage *page, CefWebEnginePage *devPage)
{
    Q_D(CefWebEngine);
    if (!page->hasBrowser())
        return;
    
    auto winId = (CefWindowHandle)devPage->property("windowId").value<quintptr>();

    CefWindowInfo info;
    info.SetAsChild(winId, CefRect(0, 0, INT_MAX, INT_MAX));

    CefBrowserSettings settings;
    reinterpret_cast<CefBrowser *>(page->browser())->GetHost()->ShowDevTools(info, d->mclient, settings, CefPoint());
}
